/*
 * Copyright 2013-present the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.kubernetes.fabric8.config;

import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClient;

import org.springframework.boot.bootstrap.ConfigurableBootstrapContext;
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator;
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator;
import org.springframework.cloud.kubernetes.commons.configdata.ConfigDataPropertiesHolder;
import org.springframework.cloud.kubernetes.commons.configdata.KubernetesConfigDataLocationResolver;
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;

import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle;

/**
 * @author Ryan Baxter
 */
public class Fabric8ConfigDataLocationResolver extends KubernetesConfigDataLocationResolver {

	@Override
	protected void registerBeans(ConfigDataLocationResolverContext resolverContext,
			ConfigDataPropertiesHolder propertiesHolder, KubernetesNamespaceProvider namespaceProvider) {

		KubernetesClientProperties kubernetesClientProperties = propertiesHolder.clientProperties();
		ConfigMapConfigProperties configMapProperties = propertiesHolder.configMapProperties();
		SecretsConfigProperties secretsProperties = propertiesHolder.secretsProperties();

		ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext();
		KubernetesClient kubernetesClient = registerConfigAndClient(bootstrapContext, kubernetesClientProperties);

		if (configMapProperties != null && configMapProperties.enabled()) {
			ConfigMapPropertySourceLocator configMapPropertySourceLocator = new Fabric8ConfigMapPropertySourceLocator(
					kubernetesClient, configMapProperties, namespaceProvider);
			if (isRetryEnabledForConfigMap(configMapProperties)) {
				configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator(
						configMapPropertySourceLocator, configMapProperties);
			}

			registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator,
					"configDataConfigMapPropertySourceLocator");
		}

		if (secretsProperties != null && secretsProperties.enabled()) {
			SecretsPropertySourceLocator secretsPropertySourceLocator = new Fabric8SecretsPropertySourceLocator(
					kubernetesClient, secretsProperties, namespaceProvider);
			if (isRetryEnabledForSecrets(secretsProperties)) {
				secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator(
						secretsPropertySourceLocator, secretsProperties);
			}

			registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator,
					"configDataSecretsPropertySourceLocator");
		}

	}

	private KubernetesClient registerConfigAndClient(ConfigurableBootstrapContext bootstrapContext,
			KubernetesClientProperties kubernetesClientProperties) {
		Config config = new Fabric8AutoConfiguration().kubernetesClientConfig(kubernetesClientProperties);
		registerSingle(bootstrapContext, Config.class, config, "fabric8Config");

		KubernetesClient kubernetesClient = new Fabric8AutoConfiguration().kubernetesClient(config);
		registerSingle(bootstrapContext, KubernetesClient.class, kubernetesClient, "configKubernetesClient",
				(ApplicationListener<ContextClosedEvent>) event -> kubernetesClient.close());
		return kubernetesClient;
	}

}
